package ds

import (
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
	"sync"
	"time"
)

type Options func(*DataSource)

type DataSource struct {
	db              *gorm.DB
	conf            *gorm.Config
	logger          logger.Interface
	maxOpenConns    int           //连接池中的最大打开连接数
	maxIdleConns    int           //连接池中最大的空闲连接数
	connMaxLifetime time.Duration //连接的最大重用时间
	connMaxIdleTime time.Duration //连接的最大空闲时间
	dsn             string        //数据库连接字符串
}

var global *gorm.DB

func SetDS(r *gorm.DB) {
	var lock sync.Mutex
	lock.Lock()
	defer lock.Unlock()
	global = r
}

func GetDS() *gorm.DB {
	return global
}

func WithConnMaxLifetime(connMaxLifetime time.Duration) Options {
	return func(opts *DataSource) {
		opts.connMaxLifetime = connMaxLifetime
	}
}

func WithConnMaxIdleTime(connMaxIdleTime time.Duration) Options {
	return func(opts *DataSource) {
		opts.connMaxIdleTime = connMaxIdleTime
	}
}

func WithMaxIdleConns(maxIdleConns int) Options {
	return func(opts *DataSource) {
		opts.maxIdleConns = maxIdleConns
	}
}

func WithMaxOpenConns(maxOpenConns int) Options {
	return func(opts *DataSource) {
		opts.maxOpenConns = maxOpenConns
	}
}

func WithLogger(l logger.Interface) Options {
	return func(opts *DataSource) {
		opts.logger = l
	}
}

func WithDBConfig(conf *gorm.Config) Options {
	return func(opts *DataSource) {
		opts.conf = conf
	}
}

func WithDBConnUrl(url string) Options {
	return func(opts *DataSource) {
		opts.dsn = url
	}
}

// 新建数据源
func NewDBConn(opts ...Options) (*gorm.DB, error) {
	conf := &gorm.Config{
		NamingStrategy: schema.NamingStrategy{SingularTable: true}, //是否采用负数表名
		Logger:         logger.Default.LogMode(logger.Info),        //打印日志级别
	}
	ds := &DataSource{conf: conf}
	for _, o := range opts {
		o(ds)
	}
	if ds.logger != nil {
		//替换日志打印
		ds.conf.Logger = ds.logger
	}

	db, err := gorm.Open(mysql.Open(ds.dsn), ds.conf)
	if err != nil {
		return nil, err
	}

	sqlDB, derr := db.DB()
	if derr != nil {
		return nil, derr
	}
	if ds.maxIdleConns != 0 {
		sqlDB.SetMaxIdleConns(ds.maxIdleConns) // 设置最大空闲连接数
	}
	if ds.maxIdleConns != 0 {
		sqlDB.SetMaxOpenConns(ds.maxOpenConns) // 设置最大打开连接数
	}
	if ds.connMaxIdleTime != 0 {
		sqlDB.SetConnMaxIdleTime(ds.connMaxIdleTime) //设置连接的最大空闲时间
	}
	if ds.connMaxLifetime != 0 {
		sqlDB.SetConnMaxLifetime(ds.connMaxLifetime) //设置连接的最大空闲时间
	}

	return db, err

}
